namespace SimpleWebServices.Data
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Net;
    using System.Transactions;
    using System.Web;
    using SimpleWebServices.Security.Cryptography;

    public sealed class RepositoryExpectations<T>
        where T : IRepository
    {
        public bool Result
        {
            get
            {
                Delete_AbsoluteUri();
                Delete_AbsoluteUriNotFound();
                Delete_AbsoluteUriNull();

                Delete_Token();
                Delete_TokenEmpty();

                Exists_AbsoluteUri();
                Exists_AbsoluteUriNotFound();
                Exists_AbsoluteUriNull();

                Exists_Token();
                Exists_TokenEmpty();

                Exists_string();
                Exists_stringEmpty();
                Exists_stringNotFound();
                Exists_stringSingleQuote();
                Exists_stringNull();

                Export_AbsoluteUri();
                Export_AbsoluteUriNull();
                Export_AbsoluteUriNotFound();
                Export_Token();
                Export_TokenEmpty();
                Export_TokenNotFound();

                Insert_IRecord();
                Insert_IRecordNull();
                Insert_IRecord_whenTokenExists();
                Insert_IRecord_whenUrnExists();
                Insert_IRecord_whenUrnNull();

                Match_AbsoluteUri_string();
                Match_AbsoluteUri_stringEmpty();
                Match_AbsoluteUri_stringNull();
                Match_AbsoluteUriNull_string();

                Match_Token_string();
                Match_Token_stringEmpty();
                Match_Token_stringNull();
                Match_TokenEmpty_string();

                ModifiedSince_AbsoluteUri_DateTimeTomorrow();
                ModifiedSince_AbsoluteUri_DateTimeYesterday();
                ModifiedSince_AbsoluteUriNull_DateTime();

                ModifiedSince_Token_DateTimeTomorrow();
                ModifiedSince_Token_DateTimeYesterday();
                ModifiedSince_TokenEmpty_DateTime();

                QueryOfT_string();
                QueryOfT_stringEmpty();
                QueryOfT_stringSingleQuote();
                QueryOfT_stringNull();

                SelectOfT_AbsoluteUri();
                SelectOfT_AbsoluteUriNotFound();
                SelectOfT_AbsoluteUriNull();

                SelectOfT_Token();
                SelectOfT_TokenEmpty();

                Token_AbsoluteUri();
                Token_AbsoluteUriNotFound();
                Token_AbsoluteUriNull();

                Update_IRecord();
                Update_IRecordNull();
                Update_IRecord_whenUrnNull();
                Upsert_IRecord_whenInserting();
                Upsert_IRecord_whenUpdating();
                Upsert_IRecordNull();

                return true;
            }
        }

        private static void Delete_AbsoluteUri()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.Delete(obj.Urn))
                {
                    throw new TestException("Delete(AbsoluteUri) failed.");
                }
                else if (null != repository.Select<RepositoryExpectationsRecord>(obj.Urn))
                {
                    throw new TestException("The object was still in the repository after Delete(AbsoluteUri).");
                }
            }
        }

        private static void Delete_AbsoluteUriNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New()
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                if (repository.Delete(obj.Urn))
                {
                    throw new TestException("Delete(AbsoluteUri) should return false when an object doesn't exist.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Delete_AbsoluteUriNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Delete(null as AbsoluteUri);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Delete(AbsoluteUri) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        private static void Delete_Token()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
                {
                    Urn = Urn.New(),
                    Value = "value"
                };

                repository.Insert(obj);

                if (!repository.Delete(obj.Token.Value))
                {
                    throw new TestException("Delete(Token) failed.");
                }
                else if (null != repository.Select<RepositoryExpectationsRecord>(obj.Token.Value))
                {
                    throw new TestException("The object was still in the repository after Delete(Token).");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Delete_TokenEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Delete(Token.Empty);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Delete(Token) should throw an ArgumentOutOfRangeException when an empty token is specified.");
                }
            }
        }

        private static void Exists_AbsoluteUri()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.Exists(obj.Urn))
                {
                    throw new TestException("Exists(AbsoluteUri) should return true when an object exists with a matching value.");
                }
            }
        }

        private static void Exists_AbsoluteUriNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();
            AbsoluteUri urn = Urn.New();

            using (TransactionScope transaction = new TransactionScope())
            {
                if (repository.Exists(urn))
                {
                    throw new TestException("Exists(AbsoluteUri) should return true when an object doesn't exist with a matching value.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Exists_AbsoluteUriNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Exists(null as AbsoluteUri);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Exists(AbsoluteUri) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        private static void Exists_Token()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.Exists(obj.Token.Value))
                {
                    throw new TestException("Exists(Token) should return true when an object exists with a matching token.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Exists_TokenEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Exists(Token.Empty);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Exists(Token) should throw an ArgumentOutOfRangeException when an empty token is specified.");
                }
            }
        }

        private static void Exists_string()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
                {
                    Urn = Urn.New(),
                    Value = Token.New()
                };

                repository.Insert(obj);

                if (!repository.Exists(string.Concat("record[@value=\"", obj.Value, "\"]")))
                {
                    throw new TestException("Exists(string) should return true when an object matches the xpath expression.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Exists_stringEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Exists(string.Empty);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Exists(string) should throw an ArgumentOutOfRangeException when an empty xpath expression is specified.");
                }
            }
        }

        private static void Exists_stringNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                if (repository.Exists(string.Concat("PersistableObject[Value=\"", Token.New(), "\"]")))
                {
                    throw new TestException("Exists(string) should return false when no object matches the xpath expression.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Exists_stringSingleQuote()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                FormatException expected = null;
                try
                {
                    repository.Exists("resource[@title='']");
                }
                catch (FormatException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Exists(string) should throw an FormatException when the xpath expression string uses single quotes.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Exists_stringNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Exists(null as string);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Exists(string) should throw an ArgumentNullException when a null xpath expression is specified.");
                }
            }
        }

        private static void Export_AbsoluteUri()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Guid.NewGuid().ToString(),
                Cacheability = HttpCacheability.Private,
                Expires = "P2D",
                Status = HttpStatusCode.Created
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                XmlDataObject actual = repository.Export(expected.Urn);

                if (expected.Urn != actual.Urn)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Urn.");
                }
                else if (expected.Token.Value != actual.Token.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Token.");
                }
                else if (expected.GetType() != actual.ObjectType)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject of the same type.");
                }
                else if (!actual.Created.HasValue)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with a Created value.");
                }
                else if (!actual.Modified.HasValue)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with a Created value.");
                }
                else if (expected.Cacheability.Value != actual.Cacheability.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Cacheability.");
                }
                else if (expected.Expires.Value != actual.Expires.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Expires.");
                }
                else if (expected.Status.Value != actual.Status.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Status.");
                }
                else if (!(bool)actual.Xml.CreateNavigator().Evaluate(string.Concat("1=count(/record[@value='", expected.Value, "'])")))
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the correct XML.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Export_AbsoluteUriNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Export(null as AbsoluteUri);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Export(AbsoluteUri) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Export_AbsoluteUriNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                AbsoluteUri urn = Urn.New();
                if (null != repository.Export(urn))
                {
                    throw new TestException("Export(AbsoluteUri) should return null when an unknown token is specified.");
                }
            }
        }

        private static void Export_Token()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Guid.NewGuid().ToString(),
                Cacheability = HttpCacheability.Private,
                Expires = "P2D",
                Status = HttpStatusCode.Created
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                XmlDataObject actual = repository.Export(expected.Token.Value);

                if (expected.Urn != actual.Urn)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Urn.");
                }
                else if (expected.Token.Value != actual.Token.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Token.");
                }
                else if (expected.GetType() != actual.ObjectType)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject of the same type.");
                }
                else if (!actual.Created.HasValue)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with a Created value.");
                }
                else if (!actual.Modified.HasValue)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with a Created value.");
                }
                else if (expected.Cacheability.Value != actual.Cacheability.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Cacheability.");
                }
                else if (expected.Expires.Value != actual.Expires.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Expires.");
                }
                else if (expected.Status.Value != actual.Status.Value)
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the same Status.");
                }
                else if (!(bool)actual.Xml.CreateNavigator().Evaluate(string.Concat("1=count(/record[@value='", expected.Value, "'])")))
                {
                    throw new TestException("Export(Token) should return an XmlDataObject with the correct XML.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Export_TokenEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Export(Token.Empty);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Export(Token) should throw an ArgumentOutOfRangeException when an empty token is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Export_TokenNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                if (null != repository.Export(Token.New()))
                {
                    throw new TestException("Export(Token) should return null when an unknown token is specified.");
                }
            }
        }

        private static void Insert_IRecord()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (Token.Empty.Equals(obj.Token.Value))
                {
                    throw new TestException("Insert(IRecord) should populate the token.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Insert_IRecordNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Insert(null as IRecord);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Insert(IRecord) should throw an ArgumentNullException when a null object is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Insert_IRecord_whenTokenExists()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                RepositoryException expected = null;
                try
                {
                    RepositoryExpectationsRecord duplicate = new RepositoryExpectationsRecord
                    {
                        Token = obj.Token,
                        Urn = Urn.New()
                    };

                    repository.Insert(duplicate);
                }
                catch (RepositoryException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Insert(IRecord) should throw an RepositoryException when an object with the token already exists.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Insert_IRecord_whenUrnExists()
        {
            IRepository repository = Activator.CreateInstance<T>();
            AbsoluteUri urn = Urn.New();

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
                {
                    Urn = Urn.New(),
                    Value = "value"
                };

                repository.Insert(obj);

                RepositoryException expected = null;
                try
                {
                    obj = new RepositoryExpectationsRecord
                    {
                        Urn = obj.Urn,
                        Value = "value"
                    };

                    repository.Insert(obj);
                }
                catch (RepositoryException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Insert(IRecord) should throw an RepositoryException when an object with the urn already exists.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Insert_IRecord_whenTokenEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryException expected = null;
                try
                {
                    RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
                    {
                        Token = Token.Empty,
                        Value = "value"
                    };

                    repository.Insert(obj);
                }
                catch (RepositoryException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Insert(IRecord) should throw an RepositoryException when an empty token is used.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Insert_IRecord_whenUrnNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryException expected = null;
                try
                {
                    repository.Insert(new RepositoryExpectationsRecord());
                }
                catch (RepositoryException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Insert(IRecord) should throw an RepositoryException when an object does not specify a URN.");
                }
            }
        }

        private static void Match_AbsoluteUri_string()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.Match(obj.Urn, MD5Hash.Compute(obj.Entity)))
                {
                    throw new TestException("Match(AbsoluteUri, string) should return true when the specified etag matches.");
                }
            }
        }

        private static void Match_AbsoluteUri_stringEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (repository.Match(obj.Urn, string.Empty))
                {
                    throw new TestException("Match(AbsoluteUri, string) should return false when the specified etag doesn't match.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Match_AbsoluteUri_stringNull()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                ArgumentNullException expected = null;
                try
                {
                    repository.Match(obj.Urn, null);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Match(AbsoluteUri, string) should throw an ArgumentNullException when a null etag is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Match_AbsoluteUriNull_string()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Match(null as AbsoluteUri, new MD5Hash("value"));
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Match(AbsoluteUri, string) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        private static void Match_Token_string()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.Match(obj.Token.Value, MD5Hash.Compute(obj.Entity)))
                {
                    throw new TestException("Match(Token, string) should return true when the specified etag matches.");
                }
            }
        }

        private static void Match_Token_stringEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (repository.Match(obj.Token.Value, string.Empty))
                {
                    throw new TestException("Match(Token, string) should return false when the specified etag doesn't match.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Match_Token_stringNull()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                ArgumentNullException expected = null;
                try
                {
                    repository.Match(obj.Token.Value, null);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Match(Token, string) should throw an ArgumentNullException when a null etag is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Match_TokenEmpty_string()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Match(Token.Empty, new MD5Hash("value"));
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Match(Token, string) should throw an ArgumentOutOfRangeException when an empty token is specified.");
                }
            }
        }

        private static void ModifiedSince_AbsoluteUri_DateTimeTomorrow()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (repository.ModifiedSince(obj.Urn, DateTime.Today.AddDays(1)))
                {
                    throw new TestException("ModifiedSince(AbsoluteUri, DateTime) should return false if the object has not been modified since the specified date.");
                }
            }
        }

        private static void ModifiedSince_AbsoluteUri_DateTimeYesterday()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.ModifiedSince(obj.Urn, DateTime.Today.AddDays(-1)))
                {
                    throw new TestException("ModifiedSince(AbsoluteUri, DateTime) should return true if the object has been modified since the specified date.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void ModifiedSince_AbsoluteUriNull_DateTime()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.ModifiedSince(null as AbsoluteUri, DateTime.UtcNow);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("ModifiedSince(AbsoluteUri, DateTime) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        private static void ModifiedSince_Token_DateTimeTomorrow()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (repository.ModifiedSince(obj.Token.Value, DateTime.Today.AddDays(1)))
                {
                    throw new TestException("ModifiedSince(Token, DateTime) should return false if the object has not been modified since the specified date.");
                }
            }
        }

        private static void ModifiedSince_Token_DateTimeYesterday()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                if (!repository.ModifiedSince(obj.Token.Value, DateTime.Today.AddDays(-1)))
                {
                    throw new TestException("ModifiedSince(Token, DateTime) should return true if the object has been modified since the specified date.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void ModifiedSince_TokenEmpty_DateTime()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.ModifiedSince(Token.Empty, DateTime.UtcNow);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("ModifiedSince(Token, DateTime) should throw an ArgumentOutOfRangeException when an empty token is specified.");
                }
            }
        }

        private static void QueryOfT_string()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Token.New()
            };
            IList<RepositoryExpectationsRecord> actual = null;

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryExpectationsRecord obj1 = new RepositoryExpectationsRecord
                {
                    Urn = Urn.New(),
                    Value = Token.New()
                };
                repository.Insert(obj1);

                repository.Upsert(expected);

                RepositoryExpectationsRecord obj2 = new RepositoryExpectationsRecord
                {
                    Urn = Urn.New(),
                    Value = Token.New()
                };
                repository.Insert(obj2);

                actual = repository.Query<RepositoryExpectationsRecord>(string.Concat("record[@value=\"", expected.Value, "\"]"));
            }

            if (1 != actual.Count)
            {
                throw new TestException("Query<T>(string) should return objects which match the xpath expression.");
            }
            else if (expected.Token != actual[0].Token)
            {
                throw new TestException("Query<T>(string) should return the correct objects which match the xpath expression.");
            }
            else if (expected.Value != actual[0].Value)
            {
                throw new TestException("Query<T>(string) should return fully populated objects which match the xpath expression.");
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void QueryOfT_stringEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Query<RepositoryExpectationsRecord>(string.Empty);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Query<T>(string) should throw an ArgumentOutOfRangeException when an empty xpath expression string is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void QueryOfT_stringSingleQuote()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                FormatException expected = null;
                try
                {
                    repository.Query<RepositoryExpectationsRecord>("resource[@title='']");
                }
                catch (FormatException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Query<T>(string) should throw an FormatException when the xpath expression string uses single quotes.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void QueryOfT_stringNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Query<RepositoryExpectationsRecord>(null as string);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Query<T>(string) should throw an ArgumentNullException when a null xpath expression string is specified.");
                }
            }
        }

        private static void SelectOfT_AbsoluteUri()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Token.New()
            };
            RepositoryExpectationsRecord actual = null;

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                actual = repository.Select<RepositoryExpectationsRecord>(expected.Urn);
            }

            if (null == actual)
            {
                throw new TestException("Select<T>(AbsoluteUri) should return an object.");
            }
            else if (expected.Urn != actual.Urn)
            {
                throw new TestException("Select<T>(AbsoluteUri) should return an object with the correct identifier.");
            }
            else if (expected.Token != actual.Token)
            {
                throw new TestException("Select<T>(AbsoluteUri) should return an object with the correct token.");
            }
            else if (expected.Value != actual.Value)
            {
                throw new TestException("Select<T>(AbsoluteUri) should return a correctly populated object.");
            }
        }

        private static void SelectOfT_AbsoluteUriNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                AbsoluteUri urn = Urn.New();
                if (null != repository.Select<RepositoryExpectationsRecord>(urn))
                {
                    throw new TestException("Select<T>(AbsoluteUri) should return null when an unknown urn is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void SelectOfT_AbsoluteUriNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Select<RepositoryExpectationsRecord>(null as AbsoluteUri);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Select<T>(AbsoluteUri) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        private static void SelectOfT_Token()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Token.New()
            };
            RepositoryExpectationsRecord actual = null;

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                actual = repository.Select<RepositoryExpectationsRecord>(expected.Token.Value);
            }

            if (null == actual)
            {
                throw new TestException("Select<T>(Token) should return an object.");
            }
            else if (expected.Urn != actual.Urn)
            {
                throw new TestException("Select<T>(Token) should return an object with the correct identifier.");
            }
            else if (expected.Token != actual.Token)
            {
                throw new TestException("Select<T>(Token) should return an object with the correct token.");
            }
            else if (expected.Value != actual.Value)
            {
                throw new TestException("Select<T>(Token) should return a correctly populated object.");
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void SelectOfT_TokenEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentOutOfRangeException expected = null;
                try
                {
                    repository.Select<RepositoryExpectationsRecord>(Token.Empty);
                }
                catch (ArgumentOutOfRangeException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Select<T>(Token) should throw an ArgumentOutOfRangeException when an empty token is specified.");
                }
            }
        }

        private static void Token_AbsoluteUri()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };
            Token? actual = null;

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                actual = repository.Token(expected.Urn);
            }

            if (expected.Token != actual)
            {
                throw new TestException("Token(AbsoluteUri) should return the token of the matching object.");
            }
        }

        private static void Token_AbsoluteUriNotFound()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                if (null != repository.Token(Urn.New()))
                {
                    throw new TestException("Token(AbsoluteUri) should return null when an unknown urn is specified.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Token_AbsoluteUriNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Token(null as AbsoluteUri);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Token(AbsoluteUri) should throw an ArgumentNullException when a null value is specified.");
                }
            }
        }

        private static void Update_IRecord()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Token.New()
            };
            RepositoryExpectationsRecord actual = null;

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                expected.Value = Token.New();
                repository.Update(expected as IRecord);

                actual = repository.Select<RepositoryExpectationsRecord>(expected.Token.Value);
            }

            if (expected.Value != actual.Value)
            {
                throw new TestException("Update(IRecord) should overwrite the object when updating.");
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Update_IRecordNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Update(null as IRecord);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Update(IRecord) should throw an ArgumentNullException when a null object is specified.");
                }
            }
        }

        private static void Upsert_IRecord_whenInserting()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "test"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Upsert(obj);
                if (Token.Empty.Equals(obj.Token.Value))
                {
                    throw new TestException("Upsert(IRecord) should populate the token when inserting.");
                }
            }
        }

        private static void Upsert_IRecord_whenUpdating()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord expected = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = Token.New()
            };
            RepositoryExpectationsRecord actual = null;

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(expected);

                expected.Value = Token.New();
                repository.Upsert(expected as IRecord);

                actual = repository.Select<RepositoryExpectationsRecord>(expected.Token.Value);
            }

            if (expected.Value != actual.Value)
            {
                throw new TestException("Upsert(IRecord) should overwrite the object when updating.");
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Update_IRecord_whenTokenEmpty()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                RepositoryException expected = null;
                try
                {
                    RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
                    {
                        Token = Token.Empty
                    };

                    repository.Update(obj as IRecord);
                }
                catch (RepositoryException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Update(IRecord) should throw an RepositoryException when an empty token is used.");
                }
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is to ignore undesirable exception types.")]
        private static void Update_IRecord_whenUrnNull()
        {
            IRepository repository = Activator.CreateInstance<T>();
            RepositoryExpectationsRecord obj = new RepositoryExpectationsRecord
            {
                Urn = Urn.New(),
                Value = "value"
            };

            using (TransactionScope transaction = new TransactionScope())
            {
                repository.Insert(obj);

                RepositoryException expected = null;
                try
                {
                    RepositoryExpectationsRecord obj2 = new RepositoryExpectationsRecord
                    {
                        Token = obj.Token
                    };

                    repository.Update(obj2 as IRecord);
                }
                catch (RepositoryException exception)
                {
                    expected = exception;
                }
                catch (Exception)
                {
                }

                if (null == expected)
                {
                    throw new TestException("Update(IRecord) should throw an RepositoryException when an object does not specify a URN.");
                }
            }
        }

        private static void Upsert_IRecordNull()
        {
            IRepository repository = Activator.CreateInstance<T>();

            using (TransactionScope transaction = new TransactionScope())
            {
                ArgumentNullException expected = null;
                try
                {
                    repository.Upsert(null as IRecord);
                }
                catch (ArgumentNullException exception)
                {
                    expected = exception;
                }

                if (null == expected)
                {
                    throw new TestException("Upsert(IRecord) should throw an ArgumentNullException when a null object is specified.");
                }
            }
        }
    }
}